package com.qy.ibp;

import com.zzg.mybatis.generator.model.DatabaseConfig;
import com.zzg.mybatis.generator.model.DbType;
import com.zzg.mybatis.generator.model.GeneratorConfig;
import com.zzg.mybatis.generator.plugins.DbRemarksCommentGenerator;
import com.zzg.mybatis.generator.util.ConfigHelper;
import com.zzg.mybatis.generator.util.DbUtil;

import lombok.extern.java.Log;

import org.apache.commons.lang3.StringUtils;
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.api.ProgressCallback;
import org.mybatis.generator.api.ShellCallback;
import org.mybatis.generator.config.*;
import org.mybatis.generator.internal.DefaultShellCallback;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * The bridge between GUI and the mybatis generator. All the operation to
 * mybatis generator should proceed through this
 */
public class MybatisGeneratorBridge {
	private static final Logger _LOG = LoggerFactory.getLogger(MybatisGeneratorBridge.class);

	private GeneratorConfig generatorConfig;

	private DatabaseConfig selectedDatabaseConfig;

	private ProgressCallback progressCallback;

	private List<IgnoredColumn> ignoredColumns;
	
	private List<String> ignoredModelColumnList;
	

	public List<String> getIgnoredModelColumnList() {
		return ignoredModelColumnList;
	}

	public void setIgnoredModelColumnList(List<String> ignoredModelColumnList) {
		this.ignoredModelColumnList = ignoredModelColumnList;
	}

	private List<ColumnOverride> columnOverrides;

	public MybatisGeneratorBridge() {
	}

	public void setGeneratorConfig(GeneratorConfig generatorConfig) {
		this.generatorConfig = generatorConfig;
	}

	public void setDatabaseConfig(DatabaseConfig databaseConfig) {
		this.selectedDatabaseConfig = databaseConfig;
	}

	

	public void generate() throws Exception {
		
		Configuration configuration = new Configuration();
		Context context = new Context(ModelType.CONDITIONAL);
		configuration.addContext(context);
		context.addProperty("javaFileEncoding", "UTF-8");
		String connectorLibPath = ConfigHelper.findConnectorLibPath(selectedDatabaseConfig.getDbType());
		configuration.addClasspathEntry(connectorLibPath);
		// Table configuration
		TableConfiguration tableConfig = new TableConfiguration(context);
		tableConfig.setTableName(generatorConfig.getTableName());
		tableConfig.setDomainObjectName(generatorConfig.getDomainObjectName());
		tableConfig.addProperty(PropertyRegistry.ANY_ROOT_CLASS, "com.banggood.adg.common.pojo.po.SuperEntity");
		tableConfig.setInsertStatementEnabled(false);
		tableConfig.setIgnoreModelColumns(ignoredModelColumnList);
		
		if (!generatorConfig.isUseExampe()) {
			tableConfig.setUpdateByExampleStatementEnabled(false);
			tableConfig.setCountByExampleStatementEnabled(false);
			tableConfig.setDeleteByExampleStatementEnabled(false);
			tableConfig.setSelectByExampleStatementEnabled(false);
		}
		tableConfig.setCatalog(selectedDatabaseConfig.getSchema());

		// 针对 postgresql 单独配置
		if (DbType.valueOf(selectedDatabaseConfig.getDbType()).getDriverClass() == "org.postgresql.Driver") {
			tableConfig.setDelimitIdentifiers(true);
		}

		// 添加GeneratedKey主键生成
		if (StringUtils.isNoneEmpty(generatorConfig.getGenerateKeys())) {
			tableConfig.setGeneratedKey(new GeneratedKey(generatorConfig.getGenerateKeys(),
					selectedDatabaseConfig.getDbType(), true, null));
		}

		if (generatorConfig.getMapperName() != null) {
			tableConfig.setMapperName(generatorConfig.getMapperName());
		}
		// add ignore columns
		if (ignoredColumns != null) {
			ignoredColumns.stream().forEach(ignoredColumn -> {
				tableConfig.addIgnoredColumn(ignoredColumn);
			});
		}
		if (columnOverrides != null) {
			columnOverrides.stream().forEach(columnOverride -> {
				tableConfig.addColumnOverride(columnOverride);
			});
		}

		if (generatorConfig.isUseActualColumnNames()) {
			tableConfig.addProperty("useActualColumnNames", "true");
		}
		JDBCConnectionConfiguration jdbcConfig = new JDBCConnectionConfiguration();
		jdbcConfig.setDriverClass(DbType.valueOf(selectedDatabaseConfig.getDbType()).getDriverClass());
		jdbcConfig.setConnectionURL(DbUtil.getConnectionUrlWithSchema(selectedDatabaseConfig));
		jdbcConfig.setUserId(selectedDatabaseConfig.getUsername());
		jdbcConfig.setPassword(selectedDatabaseConfig.getPassword());
		// java model
		JavaModelGeneratorConfiguration modelConfig = new JavaModelGeneratorConfiguration();
		modelConfig.setTargetPackage(generatorConfig.getModelPackage());
		modelConfig.setTargetProject(
				generatorConfig.getProjectFolder() + "/" + generatorConfig.getModelPackageTargetFolder());
		// Mapper configuration
		SqlMapGeneratorConfiguration mapperConfig = new SqlMapGeneratorConfiguration();
		mapperConfig.setTargetPackage(generatorConfig.getMappingXMLPackage());
		mapperConfig.setTargetProject(
				generatorConfig.getProjectFolder() + "/" + generatorConfig.getMappingXMLTargetFolder());
		// DAO
		JavaClientGeneratorConfiguration daoConfig = new JavaClientGeneratorConfiguration();
		daoConfig.setConfigurationType("XMLMAPPER");
		daoConfig.setTargetPackage(generatorConfig.getDaoPackage());
		daoConfig.setTargetProject(generatorConfig.getProjectFolder() + "/" + generatorConfig.getDaoTargetFolder());

		context.setId("myid");
		context.addTableConfiguration(tableConfig);
		context.setJdbcConnectionConfiguration(jdbcConfig);
		context.setJavaModelGeneratorConfiguration(modelConfig);
		context.setSqlMapGeneratorConfiguration(mapperConfig);
		context.setJavaClientGeneratorConfiguration(daoConfig);
		// Comment
		CommentGeneratorConfiguration commentConfig = new CommentGeneratorConfiguration();
		commentConfig.setConfigurationType(DbRemarksCommentGenerator.class.getName());
		if (generatorConfig.isComment()) {
			commentConfig.addProperty("columnRemarks", "true");
		}
		if (generatorConfig.isAnnotation()) {
			commentConfig.addProperty("annotations", "true");
		}
		context.setCommentGeneratorConfiguration(commentConfig);
		// set java file encoding
		context.addProperty(PropertyRegistry.CONTEXT_JAVA_FILE_ENCODING, generatorConfig.getEncoding());

		// 实体添加序列化
		PluginConfiguration serializablePluginConfiguration = new PluginConfiguration();
		serializablePluginConfiguration.addProperty("type", "org.mybatis.generator.plugins.SerializablePlugin");
		serializablePluginConfiguration.setConfigurationType("org.mybatis.generator.plugins.SerializablePlugin");
		context.addPluginConfiguration(serializablePluginConfiguration);
		// toString, hashCode, equals插件
		if (generatorConfig.isNeedToStringHashcodeEquals()) {
			PluginConfiguration pluginConfiguration1 = new PluginConfiguration();
			pluginConfiguration1.addProperty("type", "org.mybatis.generator.plugins.EqualsHashCodePlugin");
			pluginConfiguration1.setConfigurationType("org.mybatis.generator.plugins.EqualsHashCodePlugin");
			context.addPluginConfiguration(pluginConfiguration1);
			PluginConfiguration pluginConfiguration2 = new PluginConfiguration();
			pluginConfiguration2.addProperty("type", "org.mybatis.generator.plugins.ToStringPlugin");
			pluginConfiguration2.setConfigurationType("org.mybatis.generator.plugins.ToStringPlugin");
			context.addPluginConfiguration(pluginConfiguration2);
		}
		// limit/offset插件
		if (generatorConfig.isOffsetLimit()) {
			if (DbType.MySQL.name().equals(selectedDatabaseConfig.getDbType())
					|| DbType.PostgreSQL.name().equals(selectedDatabaseConfig.getDbType())) {
				PluginConfiguration pluginConfiguration = new PluginConfiguration();
				pluginConfiguration.addProperty("type", "com.zzg.mybatis.generator.plugins.MySQLLimitPlugin");
				pluginConfiguration.setConfigurationType("com.zzg.mybatis.generator.plugins.MySQLLimitPlugin");
				context.addPluginConfiguration(pluginConfiguration);
			}
		}
		context.setTargetRuntime("MyBatis3");

		List<String> warnings = new ArrayList<>();
		Set<String> fullyqualifiedTables = new HashSet<>();
		Set<String> contexts = new HashSet<>();
		ShellCallback shellCallback = new DefaultShellCallback(true); // override=true
		MyBatisGenerator myBatisGenerator = new MyBatisGenerator(configuration, shellCallback, warnings);
		myBatisGenerator.generate(progressCallback, contexts, fullyqualifiedTables);
	}

	public void setProgressCallback(ProgressCallback progressCallback) {
		this.progressCallback = progressCallback;
	}

	public void setIgnoredColumns(List<IgnoredColumn> ignoredColumns) {
		this.ignoredColumns = ignoredColumns;
	}

	public void setColumnOverrides(List<ColumnOverride> columnOverrides) {
		this.columnOverrides = columnOverrides;
	}
}
